package sketch.ounit;

import sketch.instrumenter.Tracer;
import sketch.util.Checker;
import sketch.util.SketchUtil;

public class Observer {
	
	public static String NULL = "V-N-ULL";
	public static String NOT_NULL = "N-T-N-ULL";
	public static String EQUAL = "_EQUAL_";
	public static String UN_EQUAL = "_UN_EQUAL_";
	
	public static String SEP_EQUAL = "%SEP_EQUALITY%";
	
	public static String VALUE_TYPE_SEP = "@V_T@";
	
	/**
	 * Dump the assertion as testing oracle
	 * XXX distinguish string from primitive type dumping
	 * XXX add some notations to distinguish
	 * */
	public static<T> void observeExpr(T expr) {
		if(expr == null) {
			Tracer.recordValue(NULL);
		} else {
			String type = null;
		    String result = null;
		    if(SketchUtil.isPrimitiveOrBoxingType(expr.getClass())) {
		    	type = expr.getClass().getName().toString();
			    result = "" + expr;
		    } else if (expr.getClass().equals(String.class)) {
		    	type = expr.getClass().getName().toString();
			    result = expr.toString();
		    } else {
			    boolean isNull = (expr == null);
			    //System.out.println("The expression value is an object type, is it null? " + isNull);
			    result = isNull ? NULL: NOT_NULL;
		    }
		    Tracer.recordValue(result + VALUE_TYPE_SEP + type);
		}
	}
	
	
	/**
	 * Observes whether two expressions are equal or not. If they are equal, it
	 * convert them into assertEquals(expr1, expr2);
	 * or else, convert them into assertNotSame(expr1, expr2)
	 * */
	public static<T> void observeEquality(T expr1, T expr2) {
		boolean equals = false;
		if(expr1 != null) {
			if(expr2 != null) {
				equals = expr1.equals(expr2);
			}
		} else {
			if(expr2 == null) {
				equals = true;
			}
		}
		if(equals) {
			Tracer.recordValue(EQUAL);
		} else {
			Tracer.recordValue(UN_EQUAL);
		}
	}
	
	/**
	 * It checks whether expr equals to one of the objects in results.
	 * If it equals to one object, we convert this equality into assertEqual(expr, results(0));
	 * or else, we convert it into an exception: fail("The value of expr: " + expr + " does not equal
	 * to any of the value in results");
	 * XXX this method is obsoleted yet
	 * */
	public static<T> void observeExpr(T expr, T...results) {
		Checker.checkNull(results, "The results array could not be null!");
		T equalExpr = null;
		boolean found = false;
		for(T result : results) {
			if(expr == null && result == null) {
				found = true;
				break;
			} else {
				if(expr != null) {
					if (expr.equals(result)) {
						equalExpr = result;
						found = true;
						break;
					}
				} else {
					if(result.equals(expr)) {
						equalExpr = result;
						found = true;
						break;
					}
				}
			}
		}
		if(found ) {
			System.out.println("find the equal result, the equal expr is: " + equalExpr);
		} else {
			throw new RuntimeException("There is no results equal to the given expression. ");
		}
		throw new UnsupportedOperationException("observe expr is not supported. please do not call this method directly.");
	}
}